package routers

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	//log "github.com/cihub/seelog"
	"shqsoft.cn/pas3ui/base"
	"shqsoft.cn/pas3ui/popedom"
	"shqsoft.cn/pas3ui/reports"

	jwt "github.com/dgrijalva/jwt-go"
	"github.com/labstack/echo"
)

type ReptInfo struct {
	Type         string              `json:"type"`
	KeyColumns   []string            `json:"keyColumns"`
	Columns      []reports.Column    `json:"columns"`
	Params       []reports.Parameter `json:"params"`
	Groups       []reports.Group     `json:"groups"`
	Chart        reports.Chart       `json:"chart"`
	Title        string              `json:"title"`
	TitleColumns []string            `json:"titleColumns"`
	DrillDowns   []reports.DrillDown `json:"drillDowns"`
	UnitTitle    string              `json:"unitTitle"`
	CalcCols     []reports.CalcCol   `json:"calcCols"`
	HideParamBar bool                `json:"hideParamBar"`
	AnnoColumns  []reports.Column    `json:"annoColumns"`
	Remarks      string              `json:"remarks"`
}
type ReptData struct {
	Total       int                 `json:"total"`
	Datas       []map[string]string `json:"datas"`
	Annotations *ReptData           `json:"annotations"`
}

// ReportRequest 报表请求
type ReportRequest struct {
	PermID       int                 `json:"permID"`
	ConfigName   string              `json:"configName"`
	ReportParams map[string]string   `json:"reportParams"`
	WhereCauses  []base.WhereCause   `json:"whereCauses"`
	WhereAttach  string              `json:"whereAttach"`
	OrderBY      map[string]string   `json:"orderBY"`
	Offset       int                 `json:"offset"`
	Limit        int                 `json:"limit"`
	GroupByIndex int                 `json:"groupByIndex"`
	ColsDisplay  map[string]bool     `json:"colsDisplay"`
	Calcs        map[string][]string `json:"calcs"`
	Unit         int                 `json:"unit"`
}

// ReportInfoRouter ReportInfo路由
func ReportInfoRouter(c echo.Context) (err error) {
	req := c.Request()
	repReqBytes, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	var repReq ReportRequest
	if err := json.Unmarshal(repReqBytes, &repReq); err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	rep, err := reports.NewReport(repReq.ConfigName)
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	repConf := rep.GetConfig()
	var params []reports.Parameter
	var paramMap map[string]string
	params, paramMap, err = initReportParams(repReq.ConfigName, repConf, repReq.ReportParams)
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	user := c.Get("user").(*jwt.Token)
	claims := user.Claims.(*UserLoginClaims)
	if err = setReportRange(rep, claims, repReq.WhereAttach, repReq.PermID, repReq.GroupByIndex); err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	if err = rep.SetParams(paramMap, nil, nil, repReq.Calcs, nil, false, 0); err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	if repConf.Type == "cross" {
		err = rep.CreateReptData()
		if err != nil {
			return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
		}
	}
	cols, err := rep.GetColumns(true)
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	annoCols, err := rep.GetAnnoColumns()
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	title, remarks, err := rep.GetRemarks()
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	groups := repConf.Groups
	if repConf.NotFrontGroup {
		groups = nil
	}
	ri := ReptInfo{
		KeyColumns:   repConf.KeyColumns,
		Columns:      cols,
		Params:       params,
		Groups:       groups,
		Title:        title,
		TitleColumns: repConf.TitleColumns,
		Type:         repConf.Type,
		Chart:        repConf.Chart,
		DrillDowns:   repConf.DrillDowns,
		UnitTitle:    repConf.UnitTitle,
		CalcCols:     repConf.CalcCols,
		HideParamBar: repConf.HideParamBar,
		AnnoColumns:  annoCols,
		Remarks:      remarks,
	}
	return c.JSON(http.StatusOK, RespData{Data: ri})
}
func getReport(c echo.Context) (reports.Report, *ReportRequest, error) {
	req := c.Request()
	repReqBytes, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return nil, nil, err
	}
	var repReq ReportRequest
	if err := json.Unmarshal(repReqBytes, &repReq); err != nil {
		return nil, nil, err
	}
	user := c.Get("user").(*jwt.Token)
	claims := user.Claims.(*UserLoginClaims)
	rep, err := reports.NewReport(repReq.ConfigName)
	if err != nil {
		return nil, nil, err
	}
	isdi, err := popedom.IsDispIdno(claims.UserID)
	if err != nil {
		return nil, nil, err
	}
	if err = setReportRange(rep, claims, repReq.WhereAttach, repReq.PermID, repReq.GroupByIndex); err != nil {
		return nil, nil, err
	}
	if err = rep.SetParams(repReq.ReportParams, repReq.WhereCauses, repReq.OrderBY, repReq.Calcs, repReq.ColsDisplay, isdi, repReq.Unit); err != nil {
		return nil, nil, err
	}
	if err = rep.CreateReptData(); err != nil {
		return nil, nil, err
	}
	return rep, &repReq, nil
}
func getReportData(rep reports.Report, repReq *ReportRequest, userID int) (reptData *ReptData, err error) {
	datas, count, err := rep.GetDataList(repReq.Offset, repReq.Limit)
	if err != nil {
		return nil, err
	}
	// permID := repReq.PermID
	// if permID != 2102 && permID != 2103 && permID != 2202 && permID != 2204 && permID != 2207 && permID != 0 && permID != 1601 {
	// 	tx := base.MYDB.Begin()
	// 	err = tx.Exec(`INSERT INTO "t_UseLog"("UserID","PermID","UseTime") VALUES(?,?,?)`, userID, permID, time.Now()).Error
	// 	if err != nil {
	// 		tx.Rollback()
	// 		return nil, err
	// 	}
	// 	tx.Commit()
	// }
	adatas, acount, err := rep.GetAnnoDataList(0, 100)
	if err != nil {
		return nil, err
	}
	reptData = &ReptData{
		Datas: datas,
		Total: count,
		Annotations: &ReptData{
			Datas: adatas,
			Total: acount,
		},
	}
	return
}

// ReportDataRouter ReportData路由
func ReportDataRouter(c echo.Context) error {
	rep, repReq, err := getReport(c)
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	user := c.Get("user").(*jwt.Token)
	claims := user.Claims.(*UserLoginClaims)
	reptData, err := getReportData(rep, repReq, claims.UserID)
	if err != nil {
		return c.JSON(http.StatusOK, RespData{Code: 1, Message: err.Error()})
	}
	msg := fmt.Sprintf("查看报表:%s", rep.ParamsToString())
	base.LogToDB(claims.UserID, repReq.PermID, msg, c.RealIP())
	return c.JSON(http.StatusOK, RespData{Data: reptData})
}

// ReportExportRouter ReportExport路由
func ReportExportRouter(c echo.Context) error {
	rep, repReq, err := getReport(c)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, err.Error())
	}
	buff, name, err := rep.ExportXslx()
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, err.Error())
	}
	fileName := rep.GetConfig().Name + name + ".xlsx"
	fileName = base64.StdEncoding.EncodeToString([]byte(fileName))
	c.Response().Header().Set("Content-Type", "application/vnd.ms-excel")
	c.Response().Header().Set("Content-Disposition", fileName)
	user := c.Get("user").(*jwt.Token)
	claims := user.Claims.(*UserLoginClaims)
	msg := fmt.Sprintf("导出报表:%s", name)
	base.LogToDB(claims.UserID, repReq.PermID, msg, c.RealIP())
	return c.Blob(http.StatusOK, "application/vnd.ms-excel", buff.Bytes())
}

func setReportRange(rep reports.Report, claims *UserLoginClaims, whereAttach string, permID int, groupByIndex int) error {
	pTypes, err := popedom.GetUserPermissionTypes(claims.UserID, permID)
	if err != nil {
		return err
	}
	dRange := reports.UserRange
	rangeVal := claims.UserID
	if base.IsInSlice(pTypes, "4") {
		dRange = reports.AllRange
	} else if base.IsInSlice(pTypes, "L") {
		dRange = reports.Dept1Range
		rangeVal = claims.ParentOrgID
	} else if base.IsInSlice(pTypes, "3") {
		dRange = reports.Dept2Range
		rangeVal = claims.OrganID
	} else if base.IsInSlice(pTypes, "G") {
		rangeVal = claims.OrganID
	}
	istm := false
	if base.IsInSlice(pTypes, "W") {
		istm = true
	}
	err = rep.SetDataRange(pTypes, dRange, whereAttach, groupByIndex, claims.UserID, istm, rangeVal)
	return err
}
func initReportParams(repName string, repConf *reports.Config, paramMap map[string]string) ([]reports.Parameter, map[string]string, error) {
	stype := repConf.DataSourceType
	params := repConf.Params
	if paramMap == nil {
		paramMap = make(map[string]string, 5)
	}
	dataType := stype
	if dataType == "" {
		dataType = base.AppConf.MainDataSource
	}
	if dataType == "" {
		dataType = "EDW"
	}
	dataType = strings.ToUpper(dataType)
	if dataType != "ODS" && dataType != "EDW" {
		return nil, nil, fmt.Errorf("指定的数据源%s无效,必须是ODS或EDW", dataType)
	}
	if strings.HasPrefix(repName, "ods_") {
		dataType = "ODS"
	}
	plen := len(params)
	retPs := make([]reports.Parameter, plen)
	for i, param := range params {
		pv, ok := paramMap[param.Name]
		if ok {
			if param.InitVal == "" || strings.HasPrefix(param.InitVal, "#") {
				param.InitVal = pv
			} else {
				paramMap[param.Name] = param.InitVal
			}
		} else {
			if initV, err := getInitValue(param.InitVal, dataType); err == nil {
				param.InitVal = initV
				paramMap[param.Name] = initV
			} else {
				return nil, nil, err
			}
		}
		retPs[i] = param
	}
	return retPs, paramMap, nil
}
func getInitValue(initValue string, dataType string) (string, error) {
	sysDate, _, err := base.GetSYSDate(dataType)
	if err != nil {
		return "", err
	}
	if strings.HasPrefix(initValue, "#") {
		var retVal string
		switch initValue {
		case "#SYSDATE":
			retVal = sysDate.Format("2006-01-02")
		case "#MONTHFIRSTDAY":
			retVal = sysDate.Format("2006-01-") + "01"
		case "#YEARFIRSTDAY":
			retVal = sysDate.Format("2006-") + "01-01"
		case "#SYSYEAR":
			retVal = sysDate.Format("2006")
		case "#SYSMONTH":
			retVal = sysDate.Format("200601")
		case "#SYSQUARTER":
			m := sysDate.Month()
			q := ""
			if m >= 1 && m <= 3 {
				q = "1"
			} else if m >= 4 && m <= 6 {
				q = "2"
			} else if m >= 7 && m <= 9 {
				q = "3"
			} else {
				q = "4"
			}
			retVal = sysDate.Format("2006") + q
		case "#SYS_PREV_QUARTER_LAST":
			m := sysDate.Month()
			if m >= 1 && m <= 3 {
				m = 1
			} else if m >= 4 && m <= 6 {
				m = 4
			} else if m >= 7 && m <= 9 {
				m = 7
			} else {
				m = 10
			}
			sjm := time.Date(sysDate.Year(), m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
			retVal = sjm.Format("2006-01-02")
		case "#SYSNEXTMONTH":
			retVal = sysDate.AddDate(0, 1, 0).Format("2006-01-02")
		case "#PREV_QUARTER_FIRST_MONTH":
			m := sysDate.Month()
			y := sysDate.Year()
			if m >= 1 && m <= 3 {
				y = y - 1
				m = 10
			} else if m >= 4 && m <= 6 {
				m = 1
			} else if m >= 7 && m <= 9 {
				m = 4
			} else {
				m = 7
			}
			sjc := time.Date(y, m, 1, 0, 0, 0, 0, time.Local)
			retVal = sjc.Format("200601")
		case "#PREV_QUARTER_LAST_MONTH":
			m := sysDate.Month()
			y := sysDate.Year()
			if m >= 1 && m <= 3 {
				m = 1
			} else if m >= 4 && m <= 6 {
				m = 4
			} else if m >= 7 && m <= 9 {
				m = 7
			} else {
				m = 10
			}
			sjc := time.Date(y, m, 1, 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
			retVal = sjc.Format("200601")
		}
		return retVal, nil
	}
	return initValue, nil
}

type ChartCardData struct {
	Title     string              `json:"title"`
	LineDatas []map[string]string `json:"lineDatas"`
	ChainData map[string]string   `json:"chainData"`
}

// ChartCardRouter 获取首页卡片路由
func ChartCardRouter(c echo.Context) error {
	user := c.Get("user").(*jwt.Token)
	claims := user.Claims.(*UserLoginClaims)
	ptypes, err := popedom.GetUserPermissionTypes(claims.UserID, 900)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页权限出错:%s", err.Error()))
	}
	date, _, err := base.GetSYSDate("EDW")
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
	}
	cyno := c.FormValue("cyno")
	if cyno == "" {
		return echo.NewHTTPError(http.StatusBadRequest, "FormValue:cyno不能为空！")
	}
	timeLevel := c.FormValue("timeLevel")
	if timeLevel == "" {
		return echo.NewHTTPError(http.StatusBadRequest, "FormValue:timeLevel不能为空！")
	}
	title := c.FormValue("title")
	if title == "" {
		return echo.NewHTTPError(http.StatusBadRequest, "FormValue:title不能为空！")
	}
	emplLevel := "user"
	if base.InStringSlice("4", ptypes) {
		emplLevel = "all"
	} else if base.InStringSlice("L", ptypes) {
		emplLevel = "dept1"
	} else if base.InStringSlice("3", ptypes) {
		emplLevel = "dept2"
	}
	ccd := ChartCardData{
		Title: title,
	}
	var colName string
	switch title {
	case "对公存款":
		colName = "ACBL_DGCK"
	case "对公贷款":
		colName = "ACBL_DGDK"
	case "储蓄存款":
		colName = "ACBL_CK"
	case "个人贷款":
		colName = "ACBL_GRDK"
	}
	ccd.LineDatas, ccd.ChainData, err = reports.GetChartCardData("ch_empl_ywfx_acbl", *date, cyno, timeLevel, emplLevel, claims.UserID, colName)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
	}
	return c.JSON(http.StatusOK, ccd)
}

// ChartCardAllRouter 获取首页卡片路由
func ChartCardAllRouter(c echo.Context) (err error) {
	user := c.Get("user").(*jwt.Token)
	claims := user.Claims.(*UserLoginClaims)
	ptypes, err := popedom.GetUserPermissionTypes(claims.UserID, 900)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页权限出错:%s", err.Error()))
	}
	var date *time.Time
	if base.AppConf.MainDataSource == "ODS" {
		date, _, err = base.GetSYSDate("ODS")
	} else {
		date, _, err = base.GetSYSDate("EDW")
	}
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
	}
	cyno := c.FormValue("cyno")
	if cyno == "" {
		return echo.NewHTTPError(http.StatusBadRequest, "FormValue:cyno不能为空！")
	}
	timeLevel := c.FormValue("timeLevel")
	if timeLevel == "" {
		return echo.NewHTTPError(http.StatusBadRequest, "FormValue:timeLevel不能为空！")
	}
	emplLevel := "user"
	hasComp := true
	hasIndi := true
	emplID := claims.UserID
	if base.InStringSlice("4", ptypes) {
		emplLevel = "all"
	} else if base.InStringSlice("L", ptypes) {
		emplID = claims.ParentOrgID
		emplLevel = "dept1"
	} else if base.InStringSlice("3", ptypes) {
		emplID = claims.OrganID
		emplLevel = "dept2"
	}
	if !base.InStringSlice("N", ptypes) && !base.InStringSlice("V", ptypes) {
		hasComp = false
	} else if !base.InStringSlice("O", ptypes) {
		hasIndi = false
	}
	ccds := make([]ChartCardData, 0, 4)
	if hasComp {
		ccdDgck := ChartCardData{
			Title: "对公存款",
		}
		ccdDgck.LineDatas, ccdDgck.ChainData, err = reports.GetChartCardData("ch_empl_ywfx_acbl", *date, cyno, timeLevel, emplLevel, emplID, "ACBL_DGCK")
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
		}
		ccds = append(ccds, ccdDgck)
		ccdDgdk := ChartCardData{
			Title: "对公贷款",
		}
		ccdDgdk.LineDatas, ccdDgdk.ChainData, err = reports.GetChartCardData("ch_empl_ywfx_acbl", *date, cyno, timeLevel, emplLevel, emplID, "ACBL_DGDK")
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
		}
		ccds = append(ccds, ccdDgdk)
	}
	if hasIndi {
		ccdCx := ChartCardData{
			Title: "储蓄存款",
		}
		ccdCx.LineDatas, ccdCx.ChainData, err = reports.GetChartCardData("ch_empl_ywfx_acbl", *date, cyno, timeLevel, emplLevel, emplID, "ACBL_CX")
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
		}
		ccds = append(ccds, ccdCx)
		ccdGd := ChartCardData{
			Title: "个人贷款",
		}
		ccdGd.LineDatas, ccdGd.ChainData, err = reports.GetChartCardData("ch_empl_ywfx_acbl", *date, cyno, timeLevel, emplLevel, emplID, "ACBL_GRDK")
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("获取首页数据出错:%s", err.Error()))
		}
		ccds = append(ccds, ccdGd)
	}
	return c.JSON(http.StatusOK, ccds)
}
